package com.nnnu.orange.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nnnu.orange.constant.JwtClaimsConstant;
import com.nnnu.orange.constant.MessageConstants;
import com.nnnu.orange.constant.StatusConstants;
import com.nnnu.orange.exception.ObjectException;
import com.nnnu.orange.mapper.BooksMapper;
import com.nnnu.orange.mapper.BorrowingsMapper;
import com.nnnu.orange.mapper.ReservationsMapper;
import com.nnnu.orange.mapper.UsersMapper;
import com.nnnu.orange.pojo.dto.*;
import com.nnnu.orange.pojo.entity.Users;
import com.nnnu.orange.result.PageResult;
import com.nnnu.orange.service.IUsersService;
import com.nnnu.orange.utils.ThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 存储用户的详细信息 服务实现类
 * </p>
 *
 * @author zk
 * @since 2024-11-07
 */
@Service
@RequiredArgsConstructor
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {

    private final ReservationsMapper reservationsMapper;
    private final BorrowingsMapper borrowingsMapper;

    /**
     * 分页查询所有用户列表
     *
     * @param queryDto dto
     * @return 分页后的列表
     */
    @Override
    public PageResult<?> pageList(@NotNull UserQueryDto queryDto) {
        // 获取查询条件
        String username = queryDto.getUsername();
        String phone = queryDto.getPhone();
        Integer membershipType = queryDto.getMembershipType();
        Integer gender = queryDto.getGender();
        // 执行分页查询
        Page<Users> usersPage = baseMapper.selectPage(new Page<>(queryDto.getPageNum(), queryDto.getPageSize()), new QueryWrapper<Users>().lambda()
                .like(StringUtils.isNotBlank(username), Users::getUsername, username)
                .like(StringUtils.isNotBlank(phone), Users::getPhone, phone)
                .eq(membershipType != null, Users::getMembershipType, membershipType)
                .eq(gender != null, Users::getGender, gender));
        // 封装分页结果
        return new PageResult<>(usersPage.getTotal(), usersPage.getRecords());
    }

    /**
     * 为用户重置密码
     *
     * @param userId 用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetUserPassword(Integer userId) {
        // 检查用户是否存在
        Users user = baseMapper.selectById(userId);
        if (user == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND); // 用户不存在
        }

        // 使用 MD5 加密默认密码
        String hashedPassword = DigestUtil.md5Hex(JwtClaimsConstant.DEFAULT_USER_PASSWORD.getBytes());

        // 更新用户密码
        int updateCount = baseMapper.update(
                null,
                new LambdaUpdateWrapper<Users>()
                        .set(Users::getPassword, hashedPassword)
                        .eq(Users::getUserId, userId)
        );
        // 检查更新结果
        if (updateCount < 1) {
            throw new ObjectException("重置密码失败，请重试");
        }
    }

    /**
     * 用户修改信息
     *
     * @param updateDto dto
     */
    @Override
    public void updateUserInfo(@NotNull UserDto updateDto) {
        // 检查用户是否存在
        Users user = baseMapper.selectById(updateDto.getUserId());
        if (user == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND); // 用户不存在
        }
        BeanUtil.copyProperties(updateDto, user);

        if (baseMapper.updateById(user) < 1) {
            throw new ObjectException("修改信息失败，请重试");
        }
    }

    /**
     * 新增用户
     *
     * @param userDto dto
     */
    @Override
    public void saveUser(UserDto userDto) {
        if (!save(BeanUtil.copyProperties(userDto, Users.class)
                .setRegistrationDate(LocalDateTime.now())
                .setPassword(DigestUtil.md5Hex(JwtClaimsConstant.DEFAULT_USER_PASSWORD.getBytes()))
                .setProfilePictureUrl("https://hythh.oss-cn-beijing.aliyuncs.com/32242471-b50f-4247-b6cb-5e82923a61c9.jpg")
                .setIsVerified(true))) {
            throw new ObjectException("添加失败");
        }
    }

    /**
     * 批量删除用户
     *
     * @param ids 用户id列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteUser(@NotNull List<Integer> ids) {
        if (CollectionUtils.isNotEmpty(ids)) {
            // 去重处理
            List<Integer> userIds = ids.stream().distinct().toList();

            // 检查是否存在关联的预约记录
            List<Integer> usersInReservation = reservationsMapper.selectUsersInReservations(userIds);
            if (CollectionUtils.isNotEmpty(usersInReservation)) {
                throw new ObjectException("部分用户存在预约记录，无法删除：" + usersInReservation);
            }

            // 检查是否存在关联的借阅记录
            List<Integer> usersInBorrowing = borrowingsMapper.selectUsersInBorrowings(userIds);
            if (CollectionUtils.isNotEmpty(usersInBorrowing)) {
                throw new ObjectException("部分用户存在借阅记录，无法删除：" + usersInBorrowing);
            }
            // 执行批量删除用户
            int deletedCount = baseMapper.deleteBatchIds(userIds);
            if (deletedCount < userIds.size()) {
                throw new ObjectException("部分用户删除失败，请重试");
            }
        } else {
            throw new ObjectException("用户ID列表为空");
        }
    }


    /**
     * 用户注册
     *
     * @param userDto dto
     */
    @Override
    public void register(@NotNull UserRegisterDto userDto) {
        if (!save(Users.builder().registrationDate(LocalDateTime.now()).membershipType(StatusConstants.ZERO)
                .username(userDto.getUsername())
                .phone(userDto.getPhone())
                .password(DigestUtil.md5Hex(userDto.getPassword().getBytes()))
                .isVerified(false)
                .profilePictureUrl("https://hythh.oss-cn-beijing.aliyuncs.com/32242471-b50f-4247-b6cb-5e82923a61c9.jpg").build())) {
            throw new ObjectException("注册失败，联系管理员");
        }
    }

    /**
     * 用户修改密码
     *
     * @param paDto dto
     */
    @Override
    public void updatePassword(UserChangPaDto paDto) {
        // 获取当前用户
        Long userId = ThreadLocalUtil.getId();
        Users users = baseMapper.selectById(userId);
        if (users == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND);
        }
        // 校验旧密码
        String encryptedOldPassword = encryptPassword(paDto.getOldPassword());
        if (!users.getPassword().equals(encryptedOldPassword)) {
            throw new ObjectException(MessageConstants.PASSWORD_ERR);
        }

        // 校验新旧密码是否一致
        String encryptedNewPassword = encryptPassword(paDto.getNewPassword());
        if (users.getPassword().equals(encryptedNewPassword)) {
            throw new ObjectException(MessageConstants.PASSWORD_IDENTICAL);
        }

        // 更新密码
        int updated = baseMapper.update(new LambdaUpdateWrapper<Users>()
                .set(Users::getPassword, encryptedNewPassword).eq(Users::getUserId, userId));

        if (updated < 1) {
            throw new ObjectException(MessageConstants.PASSWORD_UPDATE_FAIL);
        }
    }

    /**
     * 用户登录
     *
     * @param loginDto dto
     * @return 用户实体
     */
    @Override
    public Users login(@NotNull UserLoginDto loginDto) {
        Users user = baseMapper.selectOne(new LambdaQueryWrapper<Users>()
                .eq(Users::getUsername, loginDto.getUsername()));
        if (user == null) {
            throw new ObjectException(MessageConstants.USER_NOT_FOUND);
        }
        if (user.getStatus().equals(StatusConstants.ZERO)) {
            throw new ObjectException(MessageConstants.USER_DISABLED);
        }
        String password = DigestUtil.md5Hex(loginDto.getPassword().getBytes());
        if (!user.getPassword().equals(password)) {
            throw new ObjectException(MessageConstants.USER_PASSWORD_ERR);
        }
        return user;
    }

    private @NotNull String encryptPassword(@NotNull String password) {
        return DigestUtil.md5Hex(password.getBytes());
    }

}
